import axios, { AxiosRequestConfig } from "axios"
import md5 from "md5"
import { NextApiRequestCookies } from "next/dist/server/api-utils"
const myAxios = axios.create({
    baseURL: process.env.baseURL,
    withCredentials: true,
})
myAxios.interceptors.response.use(({ data }) => {
    return data
}, err => {
    const { status, statusText } = err.response
    return Promise.reject({ status, statusText })
})
const query = {
    a: {
        b: {
            c: "GET"
        }
    },
    hello: "GET"
}
type commitCallback = (err: any | null, data?: any) => void
const dataCache = new Map<string, any>()
export class HttpFetch {
    private config: AxiosRequestConfig = {}
    private source = axios.CancelToken.source()
    public isSave = false;
    public cancel() {
        this.source.cancel()
    }
    constructor(url: string) {
        this.config.url = url;
    }
    public get() {
        this.config.method = "GET"
        return this;
    }
    public post(data: any) {
        this.config.method = "POST"
        this.config.data = data;
        return this;
    }
    /**
     * -------------------------没测试------------------------
     */
    public setCookie(cookies: NextApiRequestCookies) {
        this.config.headers = {
            cookies
        }
        return this;
    }
    /**
     * ，就是个key，一般用来保存
     */
    public static getFetchId = (http: HttpFetch) => md5(JSON.stringify(http.config))
    /**
     * 将httpFetch转换为字符串
     */
    public static getFetchJson = (http: HttpFetch) => JSON.stringify({
        method: http.config.method,
        url: http.config.url,
        data: http.config.data,
        header: http.config.headers,
        isSave: http.isSave
    })
    /**
     * 将getFetchJson的字符串转换为httpFetch
     */
    public static getHttpFetch = (fetchJson: string) => {
        try {
            const config = JSON.parse(fetchJson)
            const myFetch = new HttpFetch(config.url)
            myFetch.config.headers = config.header;
            myFetch.config.method = config.method;
            myFetch.config.data = config.data;
            myFetch.isSave = config.isSave
            return myFetch
        } catch (e) {
            return null
        }
    }
    public static save(key: string, data: any) {
        if (!key) return;
        dataCache.set(key, data)
    }
    public async commit(callback?: commitCallback) {
        const result: commitCallback = (err, data) => {
            if (!callback) {
                if (err) return Promise.reject(err)
                return data;
            }
            callback(err, data)
        }
        const saveId = HttpFetch.getFetchId(this)
        if (this.isSave) {
            if (dataCache.has(saveId)) {
                return result(null, dataCache.get(saveId))
            }
        }
        let err = null;
        //发请求，请求信息已经储存到了config
        const data = await myAxios({ ...this.config }).catch((e) => err = e)
        if (this.isSave && !err) {
            dataCache.set(saveId, data)
        }
        return result(err, data)
    }
}
type result<T> = {
    [key in keyof T]: T[key] extends string ? (data?: any) => HttpFetch : result<T[key]>
}
/**
 * 
 * @param target xx
 * @param url xx
 * @returns xx
 */
const parse = <T>(target: T, url = "") => {
    type keys = keyof T;
    const arr = <keys[]>Object.keys(target)
    return <result<T>>arr.reduce((acc, label) => {
        const path = url + "/" + label;
        const method = target[label]
        if (typeof method === "string") {
            acc[label] = (data) => {
                const type = <"GET" | "POST">method
                const http = new HttpFetch(path)
                return type === "GET" ? http.get() : http.post(data)
            }
            return acc;
        }
        acc[label] = parse(method, path)
        return acc;
    }, {} as any)
}
const http = parse(query)
export default http